package prefuse.gui;
import  org.jdesktop.layout.GroupLayout ;
/*
 * A class that control all the active in GUI
 * @author Wenyi An
 * May,2010
 */

import java.util.LinkedList;

import javax.swing.JOptionPane;
import org.jdesktop.layout.*;

import prefuse.decisiontree.*;
import prefuse.decisiontree.api.*;
import prefuse.treeview.Main;
import prefuse.treeview.StartUp;
import prefuse.vensim.VensimException;



public class InterfaceHandler {	  	
		private LoadVensimGui loadVensimUI;
	    private StartUp buildPictureUI;
	    private CreateNewTreeGui createNewTreeUI;
	    private UseExistingTreeGui useExistingTreeUI;
	    public Main controller;
	    private double rollBackValue;
	    boolean isStartByENode=false;
	    protected LinkedList<ChanceEdgeInfo> ChanceEdgeList;
	    protected LinkedList<DecisionEdgeInfo> BasicEdgeList;
	    private int newEdgeID;
	    protected int rootNodeID=0;
	    private String modelLocation;
	    private String xmlLocation;
//	    DrawControler drawControler;
	  
	    public InterfaceHandler(Main theController)
	    {
	        this.controller = theController;
	        this.createUserInterface();
	//        this.drawControler = drawControler;
	        this.BasicEdgeList=new LinkedList<DecisionEdgeInfo>();
	        this.ChanceEdgeList=new LinkedList<ChanceEdgeInfo>();
	    }
	    
	    
	    public void createUserInterface(){
	    	loadVensimUI=new LoadVensimGui(this); 
	    	loadVensimUI.setVisible(true);
	    	}
	    
//	    public void createNewTreeInterface(){
//	    	
//	    	createNewTreeUI=new CreateNewTreeGui(loadVensimUI, this);
//	    	createNewTreeUI.setVisible(true);
//	    	
//	    	}
	    
	    public void createExistingTreeInterface(){
	    	useExistingTreeUI=new UseExistingTreeGui(this.loadVensimUI,this); 
	    	useExistingTreeUI.setVisible(true);
	    	}
	    
//	    public void createPictureInterface(boolean isToDisplayGraphicalInterface){
//	    	buildPictureUI=new BuildPictureGui(this, isToDisplayGraphicalInterface);
//	    	buildPictureUI.setVisible(true);
//	    	}
	    
	    public void createPictureInterface() throws Exception{
    	buildPictureUI=new StartUp(this);
    //	buildPictureUI.setVisible(true);
    	}
	    
	    
	    public void InitVensim(String modelLocation){
			this.controller.simulationInit(modelLocation);
	        System.out.println("\n\tSimulation Init with "+ modelLocation);
		}
	    
	    public void setModelLocation(String mlocation){
	    	modelLocation = mlocation;
	    }
	    public String getModelLocation(){
	    	return modelLocation;
	    }
	    
	    public void setXmlLocation(String xlocation){
	    	xmlLocation = xlocation;
	    }
	    public String getXmlLocation(){
	    	return xmlLocation;
	    }
	    /**
	     * if load called, it uses the grabs the file name to be loaded and calls
	     * the load function from the main controller
	     *      - default load
	     * @param msgToken
	     */
		public void load(String xmlLocation)
	    {
	        // if the specified file is given
	        if(xmlLocation!=null||!xmlLocation.isEmpty())
	        {
	            this.controller.loadFromXML(xmlLocation);
	            System.out.println("\tYou have selected Load with " + xmlLocation);
	        }
	        else
	        {
	            System.err.println("\tError! No load file specified.");
	            System.out.println("\tLoading default \"RabbitExample.xml\"");
	        }
	    }
	    
	    /**
	     * If there is an exist tree, use this to run by start time
	     * @param starttime
	     */
	    public void run(/* String starttime */){
                  
//                         double startTime = Double.parseDouble(starttime.trim());         
//                         this.controller.startSimulation("Default simulation", startTime);
	    	          this.controller.startSimulation("Default simulation");
//                         System.out.println("\n\tSimulation started with " + "Default simulation" + " and " + startTime);
                    System.out.println("\n\tSimulation started with " + "Default simulation");
                  
	    }
	    
	    /**
	     * get the rollback value and check if it is right
	     */
	    public void rollback(){
	    	boolean rVal = this.controller.rollBack();
	    	
	        if(!rVal)
	        {
	            System.err.println("\n\tRollBack Error!");
	        }
	        else
	        {
	            System.out.println("\n\tRollBack Success!");
	        }
	    }
	    
	    /**
	     * get the rollback value from the tree
	     * @return rollback Value
	     */
	    public double catchRollBackValue(){

	    	this.rollBackValue = this.controller.catchRollBackFromTree();
	    	return rollBackValue;
	    	
	    }
	    
	    
	    public float[] getVariable(){
	    	return this.controller.simulationController.getvarVar();
	    }
	    
	    public float[] gettimeVariable(){
	    	return this.controller.simulationController.gettimeVar();
	    }
	    
	    public void setVdfFileName(String vName){
	    	this.controller.simulationController.setVdfName(vName);
	    }
	    public void setVariable(String variableName) throws VensimException{
	    	this.controller.simulationController.setVariable(variableName, 500);
	    }
	    
	    /**
	     * get all the vensim variable names
	     * @return an array which is include all vensim variable names
	     */
	    public String[] getVensimVarNamesbyArray(){
	    	
	    	return this.controller.getSimulationListVarNamesbyArray();
	    }
	    
	    
	    

	    /**
	     * build a tree and rootNode use rootNodeId
	     * @param treeName
	     * @param treeID
	     * @param time - default by 0.0
	     * @param varName
	     */
	    public void parseDecisionTree(String treeName,int treeID,double time,String varName)
	    {
	    		rootNodeID=treeID+1;
	    		IntermediateTreeNode rootNode = null;    	
	    		if(isStartByENode==false){
	    			rootNode = this.controller.getTreeSturcture().createDecisionNode(rootNodeID);
	    			rootNode.setSelected(true);
	    			rootNode.setTime(time);
	    			rootNode.setVariableName(varName);
	    		}
	    		else{
	    			rootNode = this.controller.getTreeSturcture().createChanceNode(rootNodeID);
	    			rootNode.setSelected(false);
	    			rootNode.setTime(time);
	    			rootNode.setVariableName(varName);
	    		}
	    		 if(rootNode == null)
	    	        {
	    			 JOptionPane.showMessageDialog(null,"The Root Node cannot be null");
	    	            throw new IllegalArgumentException("The Root Node cannot be null");
	    	        }
	    	        if(rootNode.getNodeType().equals("TerminalNode"))
	    	        {
	    	        	JOptionPane.showMessageDialog(null,"The Root Node cannot be a terminal node");
	    	            throw new IllegalArgumentException("The Root Node cannot be a terminal node");
	    	        }
	    	        if(rootNode.getSourceEdge() != null)
	    	        {
	    	        	JOptionPane.showMessageDialog(null,"The Root Node cannot have a source Edge");
	    	            throw new IllegalArgumentException("The Root Node cannot have a source Edge");
	    	        }	    	      
	    	        DecisionTree tree = this.controller.getTreeSturcture().createBasicDecisionTree(rootNode, treeID);	
	    		tree.setTreeName(treeName);
	    		this.newEdgeID=9999;    		
	    }
	    /**
	     * This function is build a tree structur by recursive
	     * @param countRemainingLayers
	     * @param ProbIndex - the current column number in event branches table
	     * @param nextNodeIDWhenEnteringNode
	     * @param Dtime - Decision edges time
	     * @param DvarName - Decision Node's vensim variable name
	     * @param Etime - Event edges time
	     * @param EvarName - Event Node's vensim variable name
	     * @param Tvarname -  Terminal Node's vensim variable name
	     * @param curTime - the current time
	     * @param isEventLayer - if this layer is Event edgeskea
	     * @return nextNodeID When Entering a Node
	     */
	    public int createTree(int countRemainingLayers,int ProbIndex,int nextNodeIDWhenEnteringNode,double Dtime,String DvarName,double Etime,String EvarName,String Tvarname,double curTime,boolean isEventLayer){	    		    	
	    	if(countRemainingLayers==0){			
	    		return nextNodeIDWhenEnteringNode;
	    	}
	    	else {	    		
				
	    		return buildBranch(countRemainingLayers,nextNodeIDWhenEnteringNode,isEventLayer,curTime,EvarName,this.controller.getTreeSturcture().getCurrentNode(),ProbIndex,Dtime,DvarName,Etime,Tvarname);	
	    	}	    	  	
	    }

	    /**
	     * 
	     * interface for create Decision Node and Event Node
	     *
	     */
	    public static interface CreateNodeClosure
	    {
	    	TreeNode CreateNode(int iNode, String EvarName, String DvarName, TreeStructureHandler h);
	    }
	    
	    /**
	     * an array for create node, [0] for create Chance Node [1] for create Decision Node
	     */
	    private CreateNodeClosure nodeCreationClosuresArray[] = new CreateNodeClosure[] { new CreateNodeClosure() { public TreeNode CreateNode(int iNode, String EvarName, String DvarName, TreeStructureHandler h) 
	    																{ 
	    																	TreeNode t = h.createChanceNode(iNode);
	    									
	    																	t.setSelected(false); 
	    																	t.setVariableName(EvarName);
	    																	return t; 
	    																	}  
	    																},
	    															new CreateNodeClosure() { 
	    																	public TreeNode CreateNode(int iNode,String EvarName, String DvarName, TreeStructureHandler h) 
	    																	{ 
	    																		TreeNode t = h.createDecisionNode(iNode); 
	    																		t.setSelected(true);
	    																		t.setVariableName(DvarName);
	    																		return t; 
	    																		
	    																		}  
	    																	} 
	    															};
	    
	    private int buildBranch(int countRemainingLayers,int nextNodeIDWhenEnteringNode,boolean isEventLayer,double tempTime,String EvarName,TreeNode sourceNode,int ProbIndex,double Dtime,String DvarName,double Etime,String Tvarname){
	    	int nextNodeForChildren = nextNodeIDWhenEnteringNode;
	    	int Listlength;
	    	if(!isEventLayer){
	    		Listlength = BasicEdgeList.size();
	    		
	    	}
	    	else{
	    		Listlength = ChanceEdgeList.size();
	    	}
	    	
	    	for(int i=0;i<Listlength;i++){
	    		int curProbIndex;
    			newEdgeID++; 
    			TreeNode  newNode = createNode(countRemainingLayers, ++nextNodeForChildren, isEventLayer, EvarName, DvarName, Tvarname, this.controller.getTreeSturcture());
    			double curTime;
	            if(!isEventLayer){
	            	curTime = tempTime+Dtime;
	            	newNode.setTime(curTime);
	            	curProbIndex = ProbIndex;
	            	this.controller.returnXmlCtr().createNewEdge("BasicEdge",newEdgeID,BasicEdgeList.get(i).getValue(),0.0, false, sourceNode, newNode,BasicEdgeList.get(i).getEdgeName());	    				    			
	            }
	            else{
	            	createNewTreeUI.updateChanceList(ProbIndex);
	            	curTime = tempTime+Etime;
	            	newNode.setTime(curTime);
	            	this.controller.returnXmlCtr().createNewEdge("ChanceEdge",newEdgeID,ChanceEdgeList.get(i).getValue(),ChanceEdgeList.get(i).getProb(),false, sourceNode, newNode, ChanceEdgeList.get(i).getEdgeName());
	            	curProbIndex = ProbIndex+1;
	            	
	            }
	            
	            nextNodeForChildren = createTree(countRemainingLayers-1,curProbIndex,nextNodeForChildren,Dtime,DvarName,Etime,EvarName,Tvarname,curTime, !isEventLayer);
            	
			}
			return nextNodeForChildren;
	    	
	    }
	    private TreeNode createNode(int countRemainingLayers, int nextNodeForChildren, boolean isEventLayer,String EvarName, String DvarName, String Tvarname, TreeStructureHandler h)
	    {
			if (countRemainingLayers > 1)
				return nodeCreationClosuresArray[isEventLayer ? 1 : 0].CreateNode(nextNodeForChildren,EvarName,DvarName, h);
			else if(countRemainingLayers == 1){
				TreeNode t = h.createTerminalNode(nextNodeForChildren);
				t.setVariableName(Tvarname);
				return t;
				}
			else
				return this.controller.getTreeSturcture().createTerminalNode(nextNodeForChildren);
	    }
	    public Main getMainControler(){
	    	return this.controller;
	    }
	    
	    
}
